Моноидом называется тройка (M, #, u), где # - ассоциативная бинарная операция на M, а u - ее единичный элемент.
Моноид полугруппа с нейтральным элементом. m # u = m = u # m
(P -> M, \f1 f2 -> \p -> f1 p # f2 p, \p -> e)
Если (M, #, e) и (P, @, u) – моноиды, то функция f :: M -> P называется гомоморфизмом между этими двумя моноидами, если f (m1 # m2) = f m1 @ f m2 для всех m1, m2 из M. чему равно u ?

Списочным гомоморфизмом называется гомоморфизм из моноида (списки, append, пустой список) в какой-либо другой моноид.
То есть, функция f называется списочным гомоморфизмом, если существует оператор #, такой, что f (xs ++ ys) = f xs # f ys. Это свойство позволяет независимо вычислить результаты применения функции для подсписков, и собрать из них результат для всего списка при помощи #.
| # | u | f | |
|---|---|---|---|
| sum | + | 0 | \x -> x | 
| length | + | 0 | \x -> 1 | 
| filter p | ++ | [] | \x -> if (p x) then [x] else [] | 
| map f | ++ | [] | \x -> f x | 
| sort | merge | [] | \x -> [x] | 
Чрезвычайно важно, что благодаря ассоциативности @, в выражении x1 @ x2 @ x3 @ ... @ xn можно расставлять скобки как угодно, вычисляя его в любом порядке (надо, однако, помнить, что @ не обязан быть коммутативным).


f ~ (map, reduce)
f [x] = map x
reduce A::[] B::[] = A @ B


© Евгений Кирпичёв
regEx = /^(a+ b* c)*$/
s0 --a--> s1
s1 --a--> s1
s1 --b--> s2
s1 --с--> s0 // bingo
s2 --b--> s2
s2 --c--> s0 // bingo
s? --?--> s3
regEx = /(a+ b* c)*/| a | b | c | |
|---|---|---|---|
| s0 | s1 | s3 | s3 | 
| s1 | s1 | s2 | s0 | 
| s2 | s3 | s2 | s0 | 
| s3 | s3 | s3 | s3 | 
эндоморфизм на S
map x = \s -> fx s  -- fx – функция-столбец
reduce f g = f . g| a | b | c | |
|---|---|---|---|
| s0 | s1 | s3 | s3 | 
| s1 | s1 | s2 | s0 | 
| s2 | s3 | s2 | s0 | 
| s3 | s3 | s3 | s3 | 

Если функция f выражается и в виде левой, и в виде правой свертки с одинаковым начальным значением (но, возможно, разной операцией #), то она является списочным гомоморфизмом - и, следовательно, допускает параллельное и инкрементальное вычисление с помощью дерева.
Операция сравнения есть везде, но равны ли наши деревья?
let a = list2tree [1,5,3,2]
a == a?полиморфизм

class Eq a where
  (==) :: a -> a -> Bool
(==) :: (Eq a) => a -> a -> Bool
instance Eq Integer where
  x == y = x ‘integerEq‘ y
data Tree a = EmptyTree | Node a (Tree a) (Tree a)
  deriving (Show, Read)
instance (Eq a) => Eq (Tree a) where
  EmptyTree == EmptyTree = True
  (Node a l1 r1) == (Node b l2 r2) =
    (a==b) && (l1 == l2) && (r1 == r2)
  _ == _ = False
class Eq a where
  (==), (/=) :: a -> a -> Bool
  x /= y = not (x == y)
class (Eq a) => Ord a where
  (<), (<=), (>=), (>) :: a -> a -> Bool
  max, min :: a -> a -> a
#==# - списки равны или являются идентичными по перевороту:
[1,2,3] #==# [1,2,3] -- True
[1,1,1] #==# [1,1,2] -- False
[1,2,3] #==# [3,2,1] -- True
class Itch a where
  (#==#) :: a -> a -> Bool
instance (Eq a) => Itch [a] where
  [] #==# [] = True
  x #==# y = (x == reverse y) || (x == y)
lol a b = a #==# b
> :t lol
lol :: Itch a => a -> a -> Bool
#==# - списки являются одинаковыми множествами (Set):
[1,2,3] #==# [1,2,3] -- True
[1,1,1] #==# [1,1,2] -- False
[1,2,3] #==# [3,2,1] -- True
[1,2,2] #==# [2,1,2] -- True
[1,2,2] #==# [1,2] -- True
[1,2,15] #==# [13] -- False